#include "common_inc.h"
#include "configurations.h"
#include "hw_keyboard.h"
#include "oled.h"
#include "iwdg.h"

#include <cstring>
#include "main.h"

#define SS_LOW HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET)
#define SS_HIGH HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET)

extern USBD_HandleTypeDef hUsbDeviceFS;
/* Component Definitions -----------------------------------------------------*/
KeyboardConfig_t config;
HWKeyboard keyboard(&hspi1);

bool reportFlag=true;
char showStr[16] = "KMap:1|Ball:off";
char dpiStr[16] = "dpi:      ";
void toggleKey(bool, bool &, bool &, unsigned long &);
void rainbowGradient(float &);

uint8_t layer = 1;
bool FNflag = false;
bool FNtoggle = false;
unsigned long FNtime = 0;
bool lastFNFlag=false;

bool FN2flag = false;
bool FN2toggle = false;
unsigned long FN2time = 0;

bool FN3flag = false;
bool FN3toggle = false;
unsigned long FN3time = 0;
bool lightOffFlag=false;
bool lastFN3Flag=false;

unsigned long nowTime = 0;
unsigned long arrowTime = 0;
unsigned long buttonTime = 0;
unsigned long lastTime = 0;

uint8_t deadZone = 10;
int16_t x_sum=0;
int16_t y_sum=0;
uint8_t mouseButton = 0;
bool buttonRelease = true;
uint16_t dpi = 0;
bool dpiUP = false;
bool dpiDOWN = false;

bool flash = true;

#define NUM_COLORS 7 // 彩虹渐变颜色数量
// 彩虹渐变的RGB颜色数组
uint8_t rainbow_colors[NUM_COLORS][3] = {
		{255, 30, 30},    // 红色
		{255, 165, 30},  // 橙色
		{255, 255, 30},  // 黄色
		{30, 255, 30},    // 绿色
		{30, 30, 255},    // 蓝色
		{75, 30, 130},   // 靛蓝色
		{148, 30, 211},  // 紫色
};
struct HWKeyboard::Color_t color = {65, 105, 225};

/* Main Entry ----------------------------------------------------------------*/
void Main()
{
  // Read config from EEPROM
  EEPROM eeprom;
  eeprom.Pull(0, config);
	if(config.dpi==255)
	{
		config.dpi=7;
		eeprom.Push(0,config);
	}
  if (config.configStatus != CONFIG_OK)
  {
    // Use default settings
    config = KeyboardConfig_t{.configStatus = CONFIG_OK, .serialNum = 123, .keyMap = {},.dpi=7};
    memset(config.keyMap, -1, 128);
    eeprom.Push(0, config);
  }

  dpi=config.dpi*100;

  sensor_config(config.dpi);
  OLED_Init();
  // OLED_Allfill();
  // HAL_Delay(200);
  OLED_Clear();

  // Keyboard Report Start
  HAL_TIM_Base_Start_IT(&htim4);
  static float t = 1;
  static bool fadeDir = true;


  while (true) // 刷新频率约为500hz 2ms
  {
		HAL_IWDG_Refresh(&hiwdg);
    fadeDir ? t++ : t--;
    if (t > 500)
      fadeDir = false;
    else if (t < 2)
      fadeDir = true;

    // OLED
    if (flash)
    {
      //将dpi，转换为字符串从dpiStr[5]开始填入
      dpiStr[5]=dpi/10000+48;
      dpiStr[6]=(dpi%10000)/1000+48;
      dpiStr[7]=(dpi%1000)/100+48;
      dpiStr[8]=(dpi%100)/10+48;
      dpiStr[9]=dpi%10+48;
			if(FN2flag)
			{
				showStr[12]='o';
				showStr[13]='n';
				showStr[14]=' ';
			}
			else
			{
				showStr[12]='o';
				showStr[13]='f';
				showStr[14]='f';
			}
      //OLED_Clear();
      showStr[5] = (uint8_t)layer + 48;
      OLED_ShowStr(0, 0, showStr, 16);
      OLED_ShowStr(0,2,dpiStr,16);
      flash = false;
    }

    //        for (uint8_t i = 0; i < HWKeyboard::LED_NUMBER; i++)
    //            keyboard.SetRgbBufferByID(i, HWKeyboard::Color_t{65, 105, 225},t/151);//151
		color={65, 105, 225};
		
		if(FN3flag!=lastFN3Flag)
		{
			lastFN3Flag=FN3flag;
			layer-=1;
			if(layer==0)layer=3;
			FN2flag=!FN2flag;
      flash=true;
		}
    if(FN3flag)//FN3关闭灯光
		{
			if(!lightOffFlag)
			{
				keyboard.SetRgbBuffer({0,0,0}, t / 5 / 151); // 151
				SS_HIGH;
				keyboard.SyncLights();//  Send RGB buffers to LEDs
				lightOffFlag=true;
			}
		}
		else
		{
			lightOffFlag=false;
			//keyboard.SetRgbBuffer(color, t / 5 / 151); // 151
			rainbowGradient(t);
			SS_HIGH;
			keyboard.SyncLights();//  Send RGB buffers to LEDs
		}

    // HAL_Delay(4);//wait for lights DMA transmition done
    // 轨迹球
    if (FN2flag || keyboard.FnPressed() || keyboard.Fn2Pressed())
    {
      burst_read();
      if (nowTime-lastTime>200)//清空未启动时轨迹球的缓冲区
      {
        x.sum=0;
        y.sum=0;
      }
      lastTime=nowTime;

      if (x.sum || y.sum || keyboard.LeftPressed() || keyboard.RightPressed() || keyboard.MidPressed()||(buttonRelease&&nowTime-buttonTime>100))
      {
				buttonRelease = false;
				if(keyboard.LeftPressed() || keyboard.RightPressed() || keyboard.MidPressed())
				{
					buttonTime=nowTime;
					buttonRelease=true;
				}
        mouseButton = 0x00;
        if (!keyboard.Fn2Pressed())
        {
          if (keyboard.FnPressed()) // FN按下时将鼠标左右键映射到键盘上(J K)
          {
            if (keyboard.LeftPressed())mouseButton |= 0x01;
            if (keyboard.RightPressed())mouseButton |= 0x02;
            if (keyboard.MidPressed())mouseButton |= 0x04;
          }
          Mouse_Send(mouseButton);
        }
      }
    }

    // 键盘
    toggleKey(keyboard.FnPressed(), FNflag, FNtoggle, FNtime);
    toggleKey(keyboard.Fn2Pressed(), FN2flag, FN2toggle, FN2time);
    toggleKey(keyboard.FnPressed()&&keyboard.Fn2Pressed(), FN3flag, FN3toggle, FN3time);
		
		if(FNflag!=lastFNFlag)
		{
			layer++;
			if(layer==4)layer=1;
			lastFNFlag=FNflag;
		}
    if(keyboard.FnPressed()&&keyboard.Fn2Pressed())
    {
      keyboard.Remap(7);  //进入轨迹球dpi调整模式
      if(keyboard.dpiUPPressed())
      {
        dpiUP=true;
      }
      else if(dpiUP)
      {
        dpiUP=false;
        if(config.dpi<120)config.dpi++;
				pmw3360_init(config.dpi);
        dpi=config.dpi*100;
        eeprom.Push(0, config);
        flash=true;
      }
      if(keyboard.dpiDOWNPressed())
      {
        dpiDOWN=true;
      }
      else if(dpiDOWN)
      {
        dpiDOWN=false;
        if(config.dpi>2)config.dpi--;
				pmw3360_init(config.dpi);
        dpi=config.dpi*100;
        eeprom.Push(0, config);
        flash=true;
      }
    }
    else
    {
      if (keyboard.FnPressed())
        keyboard.Remap(layer+3);
      else
        keyboard.Remap(layer);
    }

    if (keyboard.Fn2Pressed()) // 将轨迹球的x y轴映射到键盘的上下左右,这里要清空x y sum
    {
			reportFlag=1;
      // 1.映射到上下左右 并设置死区 仅采用x y中绝对值较大的轴
      // 控制按键的频率
			keyboard.Release(keyboard.RIGHT_ARROW);
      keyboard.Release(keyboard.LEFT_ARROW);
      keyboard.Release(keyboard.DOWN_ARROW);
      keyboard.Release(keyboard.UP_ARROW);
			
			deadZone=dpi/5;
			if (nowTime - arrowTime >10)
      {
        arrowTime = nowTime;
				if (abs(x.sum) > abs(y.sum))
				{
					x_sum+=x.sum;
					if (x_sum> deadZone)
						keyboard.Press(keyboard.RIGHT_ARROW);
					else if (x_sum < -deadZone)
						keyboard.Press(keyboard.LEFT_ARROW);
					if (abs(x_sum)>deadZone)x_sum=0;
				}
				else
				{
					y_sum+=y.sum;
					if (y_sum > deadZone)
						keyboard.Press(keyboard.UP_ARROW);
					else if (y_sum < -deadZone)
						keyboard.Press(keyboard.DOWN_ARROW);
					if (abs(y_sum)>deadZone)y_sum=0;
				}
				x.sum = 0;
				y.sum = 0;
			}
    }

		if(keyboard.anyKeyPressed())reportFlag=1;
		if(reportFlag)
		{
			if(!keyboard.anyKeyPressed())reportFlag=0;
			// Report HID key states
			while(USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS,
                               CUSTOM_HID_EP2IN_ADDR,
                               keyboard.GetHidReportBuffer(1),
                               HWKeyboard::KEY_REPORT_SIZE));
		}
  }
}

/* Event Callbacks -----------------------------------------------------------*/
extern "C" void OnTimerCallback() // 1000Hz callback
{
  nowTime++;
	keyboard.ScanKeyStates(); // Around 40us use 4MHz SPI clk
	keyboard.ApplyDebounceFilter(200);
}

void toggleKey(bool status, bool &flag, bool &lastStatus, unsigned long &time)
{
  if (status != lastStatus)
  {
    if (status)
    {
      time = nowTime;
    }
    else
    {
      if (nowTime - time < 400) // 当按键单击时，400ms内松开，切换状态
      {
        flag = !flag;
        flash = true;
      }
    }
    lastStatus = status;
  }
}

void rainbowGradient(float &t)
{
    static uint8_t color_index = 0;

    uint8_t color1[3],color2[3];
		memcpy(color1,rainbow_colors[color_index],sizeof(rainbow_colors[color_index]));
    memcpy(color2,rainbow_colors[(color_index + 1) % NUM_COLORS],sizeof(rainbow_colors[(color_index + 1) % NUM_COLORS]));

    uint8_t r = color1[0] + ((color2[0] - color1[0]) * t) / 255;
    uint8_t g = color1[1] + ((color2[1] - color1[1]) * t) / 255;
    uint8_t b = color1[2] + ((color2[2] - color1[2]) * t) / 255;
		color={r,g,b};
    // 将计算得到的RGB值应用到灯光控制器
    keyboard.SetRgbBuffer(color,1);

    // t增加，控制渐变速度
    if (t > 255)
    {
        t = 0;
        color_index = (color_index + 1) % NUM_COLORS;
    }
}

extern "C" void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
  if (hspi == &hspi2)
  {
    keyboard.isRgbTxBusy = false;
  }
}

extern "C" void HID_RxCpltCallback(uint8_t *_data)
{
}
